package models

import (
	"errors"
	"fmt"
	//	"reflect"
	"gitee.com/lzqysoft/ims/libs/params"
	"strings"
	"time"

	//	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

type Organization struct {
	Id          string         `orm:"column(id);pk"`
	RegId       string         `orm:"column(reg_id)"`
	Name        string         `orm:"column(name)"`
	Seq         int            `orm:"column(seq)"`
	Status      int            `orm:"column(status)"`
	Code        string         `orm:"column(code);null"`
	Abbr        string         `orm:"column(abbr);null"`
	Type        int            `orm:"column(type)"`
	Pid         string         `orm:"column(pid);null"`
	Logo        string         `orm:"column(logo);null"`
	Title       string         `orm:"column(title);null"`
	Userlimit   int            `orm:"column(userlimit)"`
	Contact     string         `orm:"column(contact);null"`
	Phone       string         `orm:"column(phone);null"`
	FeeType     string         `orm:"column(fee_type)"`
	OrderCode   string         `orm:"column(order_code);null"`
	OrderId     string         `orm:"column(order_id);null"`
	ProdId      string         `orm:"column(prod_id);null"`
	Btime       time.Time      `orm:"column(btime);type(timestamp with time zone)"`
	Etime       time.Time      `orm:"column(etime);type(timestamp with time zone)"`
	Remark      string         `orm:"column(remark);null"`
	Isdelete    int64          `orm:"column(isdelete)"`
	Ctime       time.Time      `orm:"column(ctime);type(timestamp with time zone)"`
	Creater     string         `orm:"column(creater)"`
	Utime       time.Time      `orm:"column(utime);type(timestamp with time zone)"`
	Updater     string         `orm:"column(updater)"`
	Context     string         `orm:"column(context)"`
	User        []*User        `orm:"reverse(many)"`
	Bulletin    []*Bulletin    `orm:"reverse(many)"`
	Video       []*Video       `orm:"reverse(many)"`
	Livechannel []*Livechannel `orm:"reverse(many)"`
	Dept        []*Dept        `orm:"reverse(many)"`
}

func (t *Organization) TableName() string {
	return "sys_organization"
}

func init() {
	orm.RegisterModel(new(Organization))
}

// AddOrganization insert a new Organization into database and returns
// last inserted Id on success.
func AddOrganization(m *Organization) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetOrganizationById retrieves Organization by Id. Returns error if
// Id doesn't exist
func GetOrganizationById(id string) (v *Organization, err error) {
	o := orm.NewOrm()
	v = &Organization{Id: id}
	err = o.Read(v)
	return
}

// GetAllOrganization retrieves all Organization matches certain condition. Returns empty list if
// no records exist
func GetAllOrganization(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Organization))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		qs = qs.Filter(k, v)
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []orm.Params
	qs = qs.OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).Values(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				r, err := GetOrganizationById(v["Pid"].(string))
				if err == nil && len(r.Name) > 0 {
					v["Pname"] = r.Name
				} else {
					v["Pname"] = "顶级组织"
				}
				v["Sname"] = params.GetStatus(int(v["Status"].(int64)))
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				//				val := reflect.ValueOf(v)
				for _, fname := range fields {
					//					m[fname] = val.FieldByName(fname).Interface()
					m[fname] = v[fname]
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateOrganization updates Organization by Id and returns error if
// the record to be updated doesn't exist
func UpdateOrganizationById(m *Organization) (err error) {
	o := orm.NewOrm()
	v := Organization{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteOrganization deletes Organization by Id and returns error if
// the record to be deleted doesn't exist
func DeleteOrganization(id string) (err error) {
	o := orm.NewOrm()
	v := Organization{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&Organization{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}

//Desc 软删除组织，根据id，删除其下所有用户、公告、频道,视频数据物理删除
//Param id int64
//Param uname string
//return error
func SoftDeleteOrganization(id string, uname string) (err error) {
	o := orm.NewOrm()

	// err = o.Begin() // 事务处理过程
	query := map[string]interface{}{
		"id": id,
	}
	_, err = SoftDelete(o, "sys_organization", query, uname)
	//	用户
	// query = map[string]interface{}{
	// 	"Organization__ID": id,
	// }
	// _, err = SoftDelete(o, "user", query, uname)
	// if err != nil {
	// 	err = o.Rollback()
	// }
	//	公告
	//	query = map[string]interface{}{
	//		"Organization__ID": id,
	//	}
	//	_, err = SoftDelete(o, "Bulletin", query, uname)
	//	if err != nil {
	//		err = o.Rollback()
	//	}
	//	//	频道
	//	query = map[string]interface{}{
	//		"Organization__ID": id,
	//	}
	//	_, err = SoftDelete(o, "Live", query, uname)
	//	if err != nil {
	//		err = o.Rollback()
	//	}
	// 此过程中的所有使用 o Ormer 对象的查询都在事务处理范围内
	// if err != nil {
	// 	err = o.Rollback()
	// } else {
	// 	err = o.Commit()
	// }
	//	开始删除视频
	// videolist, _, _ := GetVideoListByOrgid(id, 0)
	// for _, value := range videolist {
	// 	err = DeleteVideo(value.Id)
	// }
	return
}

//Desc 获取所有单位
//return []Organization,error
func GetAllOrgList() ([]Organization, error) {
	var orgList []Organization
	sql := "SELECT * FROM public.sys_organization ta WHERE ta.isdelete=0"
	o := orm.NewOrm()
	_, err := o.Raw(sql).QueryRows(&orgList)
	return orgList, err
}

//Desc 验证客户合法
//Param 客户id
//return Organization, error
func CheckOrganization(id string) bool {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Organization)).Filter("id", id).Filter("Isdelete", 0).Filter("status", 1)
	return qs.Exist()
}

//Desc 获取全部上级单位id
//Param 客户id ,pids *[]int64
//return pids *[]int64
func GetParentOrg(id string, pids *[]string) {
	o := orm.NewOrm()
	var org Organization
	qs := o.QueryTable(new(Organization)).Filter("id", id).Filter("Isdelete", 0).Filter("status", 1)
	count, _ := qs.All(&org)
	if count > 0 {
		*pids = append(*pids, org.Pid)
		GetParentOrg(org.Pid, pids)
	}
}

//Desc 获取全部下级单位id
//Param 客户id ,pids *[]int64
//return pids *[]int64
func GetChildrenOrg(id string, ids *[]string) {
	o := orm.NewOrm()
	var org []Organization
	qs := o.QueryTable(new(Organization)).Filter("pid", id).Filter("Isdelete", 0).Filter("status", 1)
	count, _ := qs.Limit(-1).All(&org)
	if count > 0 {
		for _, v := range org {
			*ids = append(*ids, v.Id)
			GetChildrenOrg(v.Id, ids)
		}
	}

}
